package lxs.swift.collector.tuple;

import org.jetbrains.annotations.NotNull;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

public interface Tuple extends Serializable {

    Object[] toArray();

    default Stream<Object> stream() {
        return Arrays.stream(toArray());
    }

    default List<Object> toList() {
        Object[] array = toArray();
        return Arrays.asList(array);
    }

    static <T, TP extends Tuple> void fill(@NotNull TP tuple, int size, @NotNull Iterable<T> iterable) {
        Objects.requireNonNull(tuple);
        Objects.requireNonNull(iterable);
        if (size <= 0) {
            throw new IllegalArgumentException("size must be greater than 1");
        }
        Class<? extends Tuple> aClass = tuple.getClass();
        try {
            int num = 1;
            for (T v : iterable) {
                if (num > size) break;
                aClass.getDeclaredField("_" + num).set(tuple, v);
                num += 1;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    static <T1, T2> Tuple2<T1, T2> of(T1 _1, T2 _2) {
        return new Tuple2<>(_1, _2);
    }


    static <T> Tuple2<T, T> from2(@NotNull Iterable<T> iterable) {
        Tuple2<T, T> empty = new Tuple2<>();
        fill(empty, 2, iterable);
        return empty;
    }


    static <T1, T2, T3> Tuple3<T1, T2, T3> of(T1 _1, T2 _2, T3 _3) {
        return new Tuple3<>(_1, _2, _3);
    }


    static <T> Tuple3<T, T, T> from3(@NotNull Iterable<T> iterable) {
        Tuple3<T, T, T> empty = new Tuple3<>();
        fill(empty, 3, iterable);
        return empty;
    }


    static <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> of(T1 _1, T2 _2, T3 _3, T4 _4) {
        return new Tuple4<>(_1, _2, _3, _4);
    }


    static <T> Tuple4<T, T, T, T> from4(@NotNull Iterable<T> iterable) {
        Tuple4<T, T, T, T> empty = new Tuple4<>();
        fill(empty, 4, iterable);
        return empty;
    }


    static <T1, T2, T3, T4, T5> Tuple5<T1, T2, T3, T4, T5> of(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5) {
        return new Tuple5<>(_1, _2, _3, _4, _5);
    }


    static <T> Tuple5<T, T, T, T, T> from5(@NotNull Iterable<T> iterable) {
        Tuple5<T, T, T, T, T> empty = new Tuple5<>();
        fill(empty, 5, iterable);
        return empty;
    }


    static <T1, T2, T3, T4, T5, T6> Tuple6<T1, T2, T3, T4, T5, T6> of(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6) {
        return new Tuple6<>(_1, _2, _3, _4, _5, _6);
    }


    static <T> Tuple6<T, T, T, T, T, T> from6(@NotNull Iterable<T> iterable) {
        Tuple6<T, T, T, T, T, T> empty = new Tuple6<>();
        fill(empty, 6, iterable);
        return empty;
    }


    static <T1, T2, T3, T4, T5, T6, T7> Tuple7<T1, T2, T3, T4, T5, T6, T7> of(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7) {
        return new Tuple7<>(_1, _2, _3, _4, _5, _6, _7);
    }


    static <T> Tuple7<T, T, T, T, T, T, T> from7(@NotNull Iterable<T> iterable) {
        Tuple7<T, T, T, T, T, T, T> empty = new Tuple7<>();
        fill(empty, 7, iterable);
        return empty;
    }


    static <T1, T2, T3, T4, T5, T6, T7, T8> Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> of(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8) {
        return new Tuple8<>(_1, _2, _3, _4, _5, _6, _7, _8);
    }


    static <T> Tuple8<T, T, T, T, T, T, T, T> from8(@NotNull Iterable<T> iterable) {
        Tuple8<T, T, T, T, T, T, T, T> empty = new Tuple8<>();
        fill(empty, 8, iterable);
        return empty;
    }


    static <T1, T2, T3, T4, T5, T6, T7, T8, T9> Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9> of(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8, T9 _9) {
        return new Tuple9<>(_1, _2, _3, _4, _5, _6, _7, _8, _9);
    }


    static <T> Tuple9<T, T, T, T, T, T, T, T, T> from9(@NotNull Iterable<T> iterable) {
        Tuple9<T, T, T, T, T, T, T, T, T> empty = new Tuple9<>();
        fill(empty, 9, iterable);
        return empty;
    }

}
